import { EventsRes, MathTool } from '@amcax/base';
import { ctx2 } from '@app-cad/module';
import {
  addDimension,
  axis,
  getAngle,
  isParallel,
} from '@app-cad/common/utils';
import {
  SKETCH_CENTEREVENTS,
  sketchEventCenter,
} from '@app-cad/environments/nextcad/events/SketchEventCenter';
import { Vector2tuple, Vector3 } from 'three-legacy';
import CmdBase from '../../CmdBase';
import { dimRender } from '../cmd-render-pick/render';
import { DimAngleTool } from '../dimension/DimAngleTool';
import { AnnotationType } from '../dimension/types';
import { MouseState, State } from './types';

export default class CmdInteractor extends CmdBase {
  drawState: MouseState = State.NONE;
  curveIds: string[] = [];
  labelPosLV: Vector3 = null;
  dimAngle: DimAngleTool = null;
  radius: number = 0;
  center: Vector3 = null;
  isExist: boolean = false;
  lineVertices: Vector2tuple[][] = [];
  angle: number = 0;
  lineVecs: Vector3[] = [];
  isReserve: boolean = false;
  fistLineType: 'nomal' | 'axis' = null;

  constructor() {
    super();
    this.registerEvents();
    this.picker.clickNull();
  }

  reset() {
    this.drawState = State.NONE;
    this.pickSnapInfo = null;
    this.curveIds = [];
    this.lineVecs = [];
  }

  unregisterEvents() {
    sketchEventCenter()
      .off(SKETCH_CENTEREVENTS.POINTERUP, this.onMouseDown)
      .off(SKETCH_CENTEREVENTS.POINTERMOVE, this.onMouseMove)
      .off(SKETCH_CENTEREVENTS.KEYUP, this.onKeyUp)
      .setDefault();
  }

  registerEvents() {
    sketchEventCenter()
      .setState('dimAngle')
      .on(SKETCH_CENTEREVENTS.POINTERUP, this.onMouseDown)
      .on(SKETCH_CENTEREVENTS.POINTERMOVE, this.onMouseMove)
      .on(SKETCH_CENTEREVENTS.KEYUP, this.onKeyUp)
      .addExit(this.destroy.bind(this));
  }

  onMouseDown = ({ button }: EventsRes) => {
    if (button.onLeft && this.pickSnapInfo?.type === 'Line') {
      const vertice = this.pickSnapInfo.vertices;
      if (this.pickSnapInfo.type === 'Line') {
        this.lineVecs.push(
          new Vector3(
            vertice[1][0] - vertice[0][0],
            vertice[1][1] - vertice[0][1],
            0,
          ),
        );
        if (
          this.pickSnapInfo.id === axis[0] ||
          this.pickSnapInfo.id === axis[1]
        ) {
          if (this.fistLineType === 'axis') {
            this.lineVecs.pop();
            return;
          }
          this.isReserve = this.lineVecs.length === 2;
          this.fistLineType = 'axis';
        } else {
          this.fistLineType = 'nomal';
        }
      }
      if (this.drawState === State.NONE) {
        this.lineVertices = [];
        this.lineVertices.push(this.pickSnapInfo.vertices);
        this.curveIds.push(this.pickSnapInfo.id);
        this.drawState = State.START;
      } else if (
        this.drawState === State.START &&
        !this.curveIds.includes(this.pickSnapInfo.id)
      ) {
        const parallel = isParallel(this.lineVecs[0], this.lineVecs[1]); // 判断两个向量是否平行
        if (!parallel) {
          this.lineVertices.push(this.pickSnapInfo.vertices);
          this.curveIds.push(this.pickSnapInfo.id);
          this.drawState = State.DRAW;
          this.addLine();
        } else {
          this.lineVecs.pop();
          this.reset();
        }
      }
    } else if (button.onRight && !this.closeRightClick) {
      this.drawState = State.NONE;
      this.reset();
      this.releaseObjects();
    }
  };
  onMouseMove = (e: EventsRes) => {
    this.setMouseWV(e, false, false);
    if (this.drawState === State.DRAW) {
      this.dimAngle.update({
        labelPos: this.mouseWV,
      });
      ctx2.viewer.requestRender();
    }
  };
  addLine = () => {
    this.dimAngle = new DimAngleTool({
      lineVertices: !this.isReserve
        ? this.lineVertices
        : this.lineVertices.reverse(),
      curveIds: !this.isReserve ? this.curveIds : this.curveIds.reverse(),
      dimConstraint: AnnotationType.AngleAnno,
      labelPos: this.mouseWV,
      callback: (status) => {
        if (status === 'focus' && this.drawState === State.DRAW) {
          this.drawState = State.INPUT;
        } else if (this.drawState === State.INPUT && status === 'blur') {
          this.finishDraw();
          this.reset();
        }
      },
    });
    this.isExist = dimRender().isExistDim({
      objects: this.curveIds,
      type: 5,
    });
    if (this.isExist) {
      this.dimAngle.setDisable();
    }
    this.dimAngle.addTo(this.assisGroup);
    this.dimAngle?.labelFoucs();
  };

  // 获取线段的角 判断是否平行
  getLineAngle() {
    const lineVec = [];
    const angles = [];
    this.lineVertices.forEach((item) => {
      const lineStart = new Vector3(item[0][0], item[0][1], 0);
      const lineEnd = new Vector3(item[1][0], item[1][1], 0);
      lineVec.push(new Vector3().subVectors(lineEnd, lineStart).normalize());
      angles.push(getAngle(lineEnd, lineStart));
    });
    const angle = lineVec[1].angleTo(lineVec[0]);
    const angleC = angles[0] + Math.PI * 2 - angles[1];
    this.angle = MathTool.radToDeg(
      2 * Math.PI - (angleC > Math.PI * 2 ? angleC - Math.PI * 2 : angleC),
    );
    return angle === 0 || angle === Math.PI;
  }

  finishDraw = async () => {
    if (this.dimAngle?.getVal() === 0) {
      this.releaseObjects();
      return;
    }
    const userData = this.dimAngle.userData;
    userData.value = this.dimAngle.getDimDeg();
    userData.points = [
      ...this.dimAngle.getPosLv(),
      ...this.dimAngle.getDimArcInfo(),
    ];
    addDimension(
      this.sketchId,
      {
        objects: this.curveIds,
        type: AnnotationType.AngleAnno,
        value: userData.value,
        points: userData.points,
      },
      this.isExist,
    ).finally(() => {
      this.releaseObjects();
    });
  };

  releaseObjects() {
    this.assisGroup.clear();
    this.dimAngle?.destroy();
    this.dimAngle = null;
    ctx2.viewer.requestRender();
  }
}
